package com.javaspeak.concurrency.structures.map.singlethreadedtest;

import java.util.StringTokenizer;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.internal.TextListener;
import org.junit.runner.JUnitCore;

import com.javaspeak.concurrency.structures.map.ConcurrentMap;
import com.javaspeak.concurrency.structures.map.ConcurrentMapImpl;

/**
 * Tests ConcurrentMap in single thread mode.
 *
 * @author John Dickerson
 *
 */
public class ConcurrentMapSingleThreadedTest {

    public Logger logger =
        Logger.getLogger( ConcurrentMapSingleThreadedTest.class );

    /**
     * Tests that when values with the same hashcode for the keys are put in the
     * ConcurrentMap that they can be retrieved successfully
     */
    // @Test
    public void putSameHashCodeTest(){

        int bucketSize = 33;
        int numberOfKeyValuePairsDeletedBeforeHouseKeeping = 10;

        ConcurrentMap<String, String> map =
            new ConcurrentMapImpl<String, String>(
                   bucketSize, numberOfKeyValuePairsDeletedBeforeHouseKeeping );

        map.put( "BB", "Bat" );
        map.put( "Aa", "Apple" );

        String value = map.getValue( "BB" );
        org.junit.Assert.assertEquals( "Bat", value );

        value = map.getValue( "Aa" );
        org.junit.Assert.assertEquals( "Apple", value );

        logger.debug( map.debug() );

        StringTokenizer endOfLineTokenizer =
            new StringTokenizer( map.debug(), "\n" );

        org.junit.Assert.assertEquals(
                "Index 0 : BB:Bat ==> Aa:Apple ==> null bucket",
                endOfLineTokenizer.nextToken() );

        org.junit.Assert.assertEquals(
                "Index 1 : null keyValuePair ==> null bucket", endOfLineTokenizer.nextToken() );

    }


    /**
     * Tests that when values with the same hashcode for the keys are put in the
     * ConcurrentMap that they can be retrieved successfully
     */
    // @Test
    public void removeTest(){

        int bucketSize = 33;
        int numberOfKeyValuePairsDeletedBeforeHouseKeeping = 2;

        ConcurrentMap<String, String> map =
            new ConcurrentMapImpl<String, String>(
                   bucketSize, numberOfKeyValuePairsDeletedBeforeHouseKeeping );

        map.put( "BB", "Bat" );
        map.put( "Aa", "Apple" );
        
        logger.debug( map.debug() );

        String value = map.getValue( "BB" );
        org.junit.Assert.assertEquals( "Bat", value );

        value = map.getValue( "Aa" );
        org.junit.Assert.assertEquals( "Apple", value );

        map.remove( "BB" );

        logger.debug( map.debug() );

        StringTokenizer endOfLineTokenizer =
            new StringTokenizer( map.debug(), "\n" );

        org.junit.Assert.assertEquals(
                "Index 0 : null keyValuePair ==> Aa:Apple ==> null bucket",
                endOfLineTokenizer.nextToken() );

        org.junit.Assert.assertEquals(
                "Index 1 : null keyValuePair ==> null bucket",
                        endOfLineTokenizer.nextToken() );

        org.junit.Assert.assertNull( map.getValue( "BB" ) );

        map.remove( "Aa" );

        endOfLineTokenizer =
            new StringTokenizer( map.debug(), "\n" );

        org.junit.Assert.assertEquals(
                "Index 0 : null keyValuePair ==> null bucket",
                endOfLineTokenizer.nextToken() );

        logger.debug( map.debug() );
    }
    
    
    /**
     * Tests that House Keeping is triggered after 
     * numberOfKeyValuePairsDeletedBeforeHouseKeeping is deleted.
     */
    @Test
    public void removeHouseKeepingTriggeredTest(){
        
        int bucketSize = 3;
        int numberOfKeyValuePairsDeletedBeforeHouseKeeping = 2;

        ConcurrentMap<String, String> map =
            new ConcurrentMapImpl<String, String>(
                   bucketSize, numberOfKeyValuePairsDeletedBeforeHouseKeeping );

        map.put( "BB", "Bat" );
        map.put( "Aa", "Apple" );
        map.put( "CC", "Cat" );
        
        logger.debug( map.debug() );
        
        StringTokenizer endOfLineTokenizer =
                new StringTokenizer( map.debug(), "\n" );
        
        org.junit.Assert.assertEquals(
                "Index 0 : BB:Bat ==> Aa:Apple ==> null bucket",
                    endOfLineTokenizer.nextToken() );

        org.junit.Assert.assertEquals(
                "Index 1 : null keyValuePair ==> null bucket",
                    endOfLineTokenizer.nextToken() );
        
        org.junit.Assert.assertEquals(
                "Index 2 : CC:Cat ==> null bucket",
                    endOfLineTokenizer.nextToken() );
        
        map.remove( "Aa" );
        
        logger.debug( map.debug() );
        
        endOfLineTokenizer =
                new StringTokenizer( map.debug(), "\n" );
        
        org.junit.Assert.assertEquals(
                "Index 0 : BB:Bat ==> null keyValuePair ==> null bucket",
                    endOfLineTokenizer.nextToken() );

        org.junit.Assert.assertEquals(
                "Index 1 : null keyValuePair ==> null bucket",
                    endOfLineTokenizer.nextToken() );
        
        org.junit.Assert.assertEquals(
                "Index 2 : CC:Cat ==> null bucket",
                    endOfLineTokenizer.nextToken() );
        
        map.remove( "BB" );
        
        logger.debug( map.debug() );
        
        endOfLineTokenizer =
                new StringTokenizer( map.debug(), "\n" );
        
        org.junit.Assert.assertEquals(
                "Index 0 : null keyValuePair ==> null bucket",
                    endOfLineTokenizer.nextToken() );

        org.junit.Assert.assertEquals(
                "Index 1 : null keyValuePair ==> null bucket",
                    endOfLineTokenizer.nextToken() );
        
        org.junit.Assert.assertEquals(
                "Index 2 : CC:Cat ==> null bucket",
                    endOfLineTokenizer.nextToken() );
        
        map.remove( "CC" );
        
        logger.debug( map.debug() );
        
        endOfLineTokenizer =
                new StringTokenizer( map.debug(), "\n" );
        
        org.junit.Assert.assertEquals(
                "Index 0 : null keyValuePair ==> null bucket",
                    endOfLineTokenizer.nextToken() );

        org.junit.Assert.assertEquals(
                "Index 1 : null keyValuePair ==> null bucket",
                    endOfLineTokenizer.nextToken() );
        
        org.junit.Assert.assertEquals(
                "Index 2 : null keyValuePair ==> null bucket",
                    endOfLineTokenizer.nextToken() );
    }


    public static void main( String args[] ){

        BasicConfigurator.resetConfiguration();
        BasicConfigurator.configure();

        JUnitCore junitCore = new JUnitCore();
        junitCore.addListener( new TextListener( System.out ) );
        junitCore.run( ConcurrentMapSingleThreadedTest.class );
    }
}
